Medium 清新閱讀版
:連結
前一天我們介紹了在撰寫自動化測試時常使用的 Trait,今天則要來為大家介紹 Auth 相關測試可如何進行,同時為大家示範 RefreshDatabase
與 WithoutMiddleware
這兩個 Trait 的使用。
在以 Laravel 開發 Web 服務時,常常以 Auth::user()
這個方式,來取得當前登入 Session、當前 API 請求 Token 所關聯之使用者資料,然而在撰寫測試時,如果還要先進行模擬輸入帳密與送出登入請求,並從回應中取出 Session ID 之 Cookie 或是 API Token,再帶入實際要進行測試的行為中,那會是一個挺麻煩的事情。有鑑於此,Laravel 在提供了兩個函數:
$this->actingAs(UserContract $user, $guard = null)
$this->be(UserContract $user, $guard = null)
這兩個函數的功能完全一樣(實際上 $this->actingAs()
裡面就是呼叫$this->be()
),都是可以讓我們設定當前要模擬的登入/Auth之使用者。以下就讓我們看看如何使用吧!(由於官方文件主要是使用 $this->actingAs()
,因此以下範例也主要會使用 $this->actingAs()
)
routes/web.php
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
Route::get('/me/profiles', function (Request $request) {
$user = Auth::user();
$profile = [
'name' => $user->name,
'email' => $user->email,
];
return response()->json(['profile' => $profile]);
})->name('get.me.profile')
->middleware(['auth']);
在以上的程式碼中,我們實作了一個 API 端點,此端點可取得當前所登入的 User 個人檔案資料,並且以JSON格式回應。
tests/Feature/AuthTest.php
<?php
namespace Tests\Feature;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class AuthTest extends TestCase
{
use RefreshDatabase
public function testGetLoggedInUserProfile()
{
$user = User::factory()->create();
$this->actingAs($user)->get(route('get.me.profile'))
->assertJson([
'profile' => [
'name' => $user->name,
'email' => $user->email,
]
]);
}
}
以上測試程式碼,我們建立了一筆假資料 $user
,並將其設定為當前登入之 User
,並測試是否以 get.me.profile
這個 API 端點取得使用者個人檔案資料。同時,因為我們有建立假資料,為不讓其他測試案例與此測試案例產生交互影響,我們使用了 這個 RefreshDatabase
Trait ,在每個 tests/Feature/AuthTest.php
裡的測試被執行的前後重置資料庫。
在前一天文章有提到,有時我們想測試的功能會經過一些 Middleware 的處理,有可能會需要做些特別設定,才可以正常使用欲測試的功能,但 Middleware 的處理邏輯可能不是當下想測試的重點,此時便可使用 WithoutMiddleware
來略過 Middleware 。
app/Http/Middleware/ForbidLoginDuringLunch.php
<?php
namespace App\Http\Middleware;
use Carbon\Carbon;
use Closure;
use Illuminate\Http\Request;
class ForbidLoginDuringLunch
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
$hour = Carbon::now()->hour;
if ($hour <= 14 && $hour >= 12) {
return response()->json(['error' => 'No lunch login'], 403);
}
return $next($request);
}
}
以上程式碼實作了一個 Middleware,這個 Middleware 會檢查當下時間是否介於 12~14點之間,如果是則回應 403,相當於禁止於午休時段登入網站(會不會真的有網站實作這種 Middleware?)。
routes/web.php
<?php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
Route::get('/me/profiles', function (Request $request) {
$user = Auth::user();
$profile = [
'name' => $user->name,
'email' => $user->email,
];
return response()->json(['profile' => $profile]);
})->name('get.me.profile')
->middleware(['auth', 'no.lunch.login']); // 新增 no.lunch.login Middleware
以上程式碼和前一個案例大致相同,只不過多套用了 no.lunch.login
這個 Middleware。
tests/Feature/AuthTest.php
<?php
namespace Tests\Feature;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Tests\TestCase;
class AuthTest extends TestCase
{
use RefreshDatabase;
use WithoutMiddleware;
public function testGetLoggedInUserProfile()
{
$user = User::factory()->create();
$this->actingAs($user)->get(route('get.me.profile'))
->assertJson([
'profile' => [
'name' => $user->name,
'email' => $user->email,
]
]);
}
}
以上程式碼和前一個案例大致相同,但多使用了 WithoutMiddleware
,使用它之後,測試就能順利進行了!
以上就是今天的介紹了!不知道大家還能消化嗎?(當時筆者可是花了不少時間才了解…..)
明天來測試「指令」吧!